use std::f32::consts::PI;
use std::time::Duration;
use std::thread::sleep;
use std::mem::size_of;
use std::ptr::null_mut;
use windows_sys::Win32::Media::Audio::*;

const BPM: f32 = 100.0;
const TONE_LIST: &[i32] = &[
    // 4,4,2,4,
    // 2,0,2,0,2,2,4,-3,
    // 0,0,-3,0,
    // 0,0,0,0,0,2,4,2,
    // 2,4,2,4,
    // 2,0,2,0,0,2,4,-3,
    // 0,0,-3,0,
    // 0,-5,0,0,-5,2,0,2,
    // -5,-5,2,4,4,
    // 2,2,2,2,2,0,4,
    // 0,0,0,0,0,0,0,2,
    // -5,-5,2,4,4,
    // 2,2,2,2,2,0,4,
    // 0,0,0,0,0,0,4,2,
    -5,-5,4,7,4,2,0,0,-3,0,0,0,
    0,0,0,2,0,2,0,0,-3,-5,2,2,
    -5,-5,-5,7,4,2,0,0,-3,-3,0,-3,
    -3,4,2,2,0,4,2,0,-3,0,0,
];
// &[
//     -3, 4, 4, 4, 4, 2,
//     0, 2, 0, -1, -3,
//     9, 9, 9, 9, 7,
//     4, 7, 7, 5, 4,
//     4, 9, 9, 7, 4, 2,
//     0, 2, 0, -1, -3, -8,
//     -8, 0, 0, -1, -3, 4,
//     2, 0, -1, -5, -3,
// ];
const DURATION_LIST: &[f32] = &[
    // 0.5, 0.5, 0.5, 2.0,
    // 0.5, 0.5, 0.5, 0.75,0.5, 0.5, 0.5, 2.0,
    // 0.5, 0.5, 0.5, 2.0,
    // 0.5, 0.5, 0.5, 0.75,0.5, 0.5, 0.5, 2.0,
    // 0.5, 0.5, 0.5, 2.0,
    // 0.5, 0.5, 0.5, 0.75,0.5, 0.5, 0.5, 2.0,
    // 0.5, 0.5, 0.5, 2.0,
    // 0.5, 0.5, 0.5, 0.75,0.5, 0.5, 0.5, 2.0,
    // 0.5, 0.5, 0.5, 0.75, 1.0,
    // 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
    // 0.5, 0.5, 0.5, 0.5, 0.5, 1.0, 1.0, 1.0,
    // 0.5, 0.5, 0.5, 0.5, 0.75,
    // 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
    // 0.5, 0.5, 0.5, 1.0, 0.5, 0.5, 1.0, 2.0,
    0.5, 0.5, 0.5, 0.5, 0.5,
    0.75, 0.5, 0.5, 0.5, 0.5, 0.75, 1.0,
    0.5, 0.5, 0.5, 0.5, 0.5,
    0.75, 0.5, 0.5, 0.5, 0.5, 0.75, 1.0,
    0.5, 0.5, 0.5, 0.5, 0.75, 0.5, 0.5, 0.5, 0.5, 0.5,0.5, 1.0,
    0.5, 0.5, 0.5, 0.5, 0.5, 0.75, 1.5, 0.5, 0.5, 0.5, 3.0,
];
// &[
//     0.5, 0.5, 0.5, 0.5, 1.5, 0.5,
//     0.75, 0.25, 0.5, 0.5, 2.0,
//     0.5, 0.5, 0.5, 0.5, 1.5, 0.5,
//     0.5, 0.5, 0.5, 0.5, 2.0,
//     0.5, 0.5, 0.5, 0.5, 1.5, 0.5,
//     0.75, 0.25, 0.5, 0.5, 1.0, 1.0,
//     0.5, 0.5, 0.5, 0.5, 1.5, 0.5,
//     0.75, 0.25, 0.5, 0.5, 2.0,
// ];
fn main() {
    unsafe{
        let mut hwo : HWAVEOUT = 0;
        let wfx = WAVEFORMATEX {
            wFormatTag: WAVE_FORMAT_PCM as _ ,
            nChannels: 2,
            nSamplesPerSec: 44100,
            nAvgBytesPerSec: 44100 * 2 * 16 / 8,
            nBlockAlign: 2 * 16 / 8,
            wBitsPerSample: 16,
            cbSize: 0,
        };

        waveOutOpen(&mut hwo,WAVE_MAPPER,&wfx, 0, 0, CALLBACK_NULL | WAVE_FORMAT_DIRECT);

        let mut data: Vec<i16> = Vec::new();

        for (i,tone) in TONE_LIST.iter().enumerate() {
            let f = 523.0 * 2.0f32.powf(*tone as f32 / 12.0);
            let tone_samples = (DURATION_LIST[i] / BPM * 60.0 * 44100.0) as usize;
            for i in 0..tone_samples {
                let y = (f32::sin(2.0 * PI * f * (i as f32 / 44100.0)) * i16::MAX as f32 * 0.5) as i16;
                data.push(y);
                data.push(y);
            }
        }
        let mut wh = WAVEHDR {
            lpData: data.as_mut_ptr() as _,
            dwBufferLength: (data.len() * 2) as _,
            dwBytesRecorded: 0,
            dwUser: 0,
            dwFlags: 0,
            dwLoops: 0,
            lpNext: null_mut(),
            reserved: 0,
        };

        waveOutPrepareHeader(hwo, &mut wh, size_of::<WAVEHDR>() as _);
        waveOutWrite(hwo, &mut wh, size_of::<WAVEHDR>() as _);
        sleep(Duration::from_secs((DURATION_LIST.iter().sum::<f32>() / BPM * 60.0 + 1.0) as _));
        waveOutClose(hwo);
    }
}
